﻿using iDetector;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace DART.Detector.IRay.Wrapper
{
    /// <summary>
    /// 设备事件参数
    /// </summary>
    public class IRayEventArgs : EventArgs
    {
        /// <summary>
        /// 探测器id
        /// </summary>
        public int DetectorID { get; }

        /// <summary>
        /// IRayEvent or int
        /// </summary>
        public IRayEvent EventID { get; }

        /// <summary>
        /// EventLevel or int
        /// </summary>
        public EventLevel EventLevel { get; }

        public string Msg { get; }

        /// <summary>
        /// IRayCmd or int
        /// </summary>
        public IRayCmd Param1 { get; }

        /// <summary>
        /// IRayError or int
        /// </summary>
        public IRayError Param2 { get; }

        /// <summary>
        /// 图像数据
        /// </summary>
        public IRayImage Image { get; }

        public IRayEventArgs(int detectorID, int eventID, int eventLevel, IntPtr msgPtr,
            int param1, int param2, int ptrParamLen, IntPtr paramPtr)
        {
            DetectorID = detectorID;
            EventID = (IRayEvent)eventID;
            EventLevel = (EventLevel)eventLevel;
            Msg = Marshal.PtrToStringAnsi(msgPtr);
            Param1 = (IRayCmd)param1;
            Param2 = (IRayError)param2;
            Image = EventID == IRayEvent.Image ? IRayImage.Create(paramPtr) : null;
        }

        public override string ToString()
        {
            return $"Id:{DetectorID}, Level:{EventLevel}, Cmd:{Param1}, Code:{Param2}, Type:{EventID}, Msg:{Msg}" +
                $"{(Image != null ? $", {Image}" : "")}";
        }
    }

    /// <summary>
    /// iRay探测器图像
    /// </summary>
    public class IRayImage : GrayImage
    {
        /// <summary>
        /// 从非托管内存创建托管图像副本
        /// </summary>
        /// <param name="ptr"></param>
        internal static IRayImage Create(IntPtr ptr)
        {
            if (ptr == IntPtr.Zero) return null;
            var o = new IRayImage();
            var ticks = System.DateTime.UtcNow.Ticks;
            var image = Marshal.PtrToStructure<iDetector.IRayImage>(ptr);
            o.Data = image.GetData();
            o.Width = image.nWidth;
            o.Height = image.nHeight;
            o.BytesPerPixel = image.nBytesPerPixel;
            o.BitsPerPixel = image.nBytesPerPixel * 8;
            o.Timestamp = ticks;

            var innerTags = image.propList.ToDictionary();
            o.IsPreExposure = innerTags.TryGetValue("BinningMode", out var p) && $"{p}" == "1";
            o.Maker = innerTags.GetValue<string>("Maker", default);
            o.Model = innerTags.GetValue<string>("Model", default);
            o.XRayWindow = innerTags.GetValue<int>("XRayWindow", default);
            o.FrameRate = innerTags.GetValue<int>("FrameRate", default);
            o.FrameNo = innerTags.GetValue<int>("FrameNo", default);
            o.Temperature = innerTags.GetValue<float>("Temperature", default);
            o.RealFrequency = innerTags.GetValue<int>("RealFrequency", default);
            o.BinningMode = innerTags.GetValue<int>("BinningMode", default);
            o.CorrectFlag = innerTags.GetValue<int>("CorrectFlag", default);
            o.AvgValue = innerTags.GetValue<int>("AvgValue", default);
            o.CenterValue = innerTags.GetValue<int>("CenterValue", default);
            o.ImageEncrypt = innerTags.GetValue<int>("ImageEncrypt", default);

            return o;
        }

        private IRayImage() { }

        /// <summary>
        /// 是预曝光图像
        /// </summary>
        public bool IsPreExposure { get; internal set; }

        /// <summary>
        /// 图像UTC时间戳
        /// </summary>
        public long Timestamp { get; internal set; }

        /// <summary>
        /// XRay
        /// </summary>
        public string Maker { get; internal set; }

        /// <summary>
        /// 示例：Mammo1012X
        /// </summary>
        public string Model { get; internal set; }

        public int XRayWindow { get; internal set; }

        /// <summary>
        /// 帧率
        /// </summary>
        public int FrameRate { get; internal set; }

        /// <summary>
        /// 图像递增计数
        /// </summary>
        public int FrameNo { get; internal set; }

        /// <summary>
        /// 温度
        /// </summary>
        public float Temperature { get; internal set; }

        public int RealFrequency { get; internal set; }

        public int BinningMode { get; internal set; }

        public int CorrectFlag { get; internal set; }

        public int AvgValue { get; internal set; }

        public int CenterValue { get; internal set; }

        /// <summary>
        /// 示例：20231229135741
        /// </summary>
        public string DateTime { get; internal set; }

        /// <summary>
        /// 1加密，0无
        /// </summary>
        public int ImageEncrypt { get; internal set; }

        public override string ToString()
        {
            return $"{nameof(Width)}:{Width} {nameof(Height)}:{Height} {nameof(BitsPerPixel)}:{BitsPerPixel} " +
                $"{nameof(Timestamp)}:{Timestamp} {nameof(IsPreExposure)}:{IsPreExposure} " +
                $"{nameof(BinningMode)}:{BinningMode} {nameof(CorrectFlag)}:{CorrectFlag} " +
                $"{nameof(Temperature)}:{Temperature} {nameof(AvgValue)}:{AvgValue} " +
                $"{nameof(CenterValue)}:{CenterValue}";
        }
    }

    public static partial class IRayImageExtensions
    {
        /// <summary>
        /// 根据非托管字典生成Tags
        /// </summary>
        /// <param name="map"></param>
        /// <returns></returns>
        public static IDictionary<string, object> ToDictionary(this IRayVariantMap map)
        {
            var output = new Dictionary<string, object>();
            int itemSize = Marshal.SizeOf<IRayVariantMapItem>();
            var itemCount = map.nItemCount;
            for (int i = 0; i < itemCount; i++)
            {
                var item = Marshal.PtrToStructure<IRayVariantMapItem>(map.pItems + i * itemSize);
                output[$"{(ImageTag)item.nMapKey}"] = new IRayVariant(item.varMapVal).To<object>();
            }
            return output;
        }

        /// <summary>
        /// 获取图像中非托管数据的副本
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public static byte[] GetData(this iDetector.IRayImage image)
        {
            var length = image.nWidth * image.nHeight * image.nBytesPerPixel;
            if (image.pData == IntPtr.Zero || length == 0) return null;
            var buffer = new byte[length];
            Marshal.Copy(image.pData, buffer, 0, length);
            return buffer;
        }
    }
}